package com.example.demo.util;

import com.example.demo.exception.ParameterException;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import lombok.SneakyThrows;
import org.springframework.format.annotation.DateTimeFormat;

import java.text.SimpleDateFormat;
import java.util.Date;


public class JsonUtil {

    /**
     * 说明字段
     */
    @DateTimeFormat
    @JsonProperty("birth_ d ate") // 用于属性，把属性的名称序列化时转换为另外一个名称。
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm") //用于属性或者方法，把属性的格式序列化时转换成指定的格式。
    @JsonPropertyOrder({"birth_Date", "name"})
    private Date date;


    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /**
     * JsonInclude.Include.NON_NULL         对于值为null的字段不进行序列化
     * JsonInclude.Include.NON_ABSENT       包含了 NON_NULL 的功能，还有一些看不懂的英文。。。
     * JsonInclude.Include.NON_EMPTY        这个属性包含NON_NULL，NON_ABSENT之后还包含如果字段为空也不序列化。这个也比较常用
     * JsonJsonInclude.Include.NON_DEFAULT  这个也好理解，如果字段是默认值的话就不序列化。
     * JsonInclude.Include.ALWAYS           对所有字段都进行序列化
     * JsonInclude.Include.CUSTOM
     * JsonInclude.Include.USE_DEFAULTS
     *
     */
    static {
        //在序列化时忽略值为 null 的字段，对null的字段不进行反序列化====>JsonInclude.Include.NON_NULL
        OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        //取消默认转换timestamps形式、在序列化时日期格式默认为 yyyy-MM-dd'T'HH:mm:ss.SSSZ
        OBJECT_MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        //忽略空Bean转json的错误
        OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        //所有的日期格式都统一为以下的样式，即yyyy-MM-dd HH:mm:ss
        OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm"));
        //在反序列化时忽略在 json 中存在但 Java 对象不存在的属性
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // false ： 反序列化数组时如果没有规定类型（List 还是 Array ）就会默认序列化为 List 类型
        // true  :  Object[] 数组类型
        OBJECT_MAPPER.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, false);
        // json字符串中反序列化如果遇到找不到的字段是否抛出异常，true 抛出异常，false 不抛出异常
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //忽略值为默认值的属性                                    ··························································································································································                                                                                                              ··
        OBJECT_MAPPER.setDefaultPropertyInclusion(JsonInclude.Include.NON_DEFAULT);
        // 更多配置信息可以查看 Jackson 的 DeserializationFeature，SerializationFeature 和 Include
    }


    /**
     * 对象转换为字符串
     *
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> String obj2String(T obj) {
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new JsonException(e);
        }
    }


    /**
     * 对象转Json格式字符串(格式化的Json字符串)
     *
     * @param obj 对象
     * @return 美化的Json格式字符串
     */
    public static <T> String obj2StringPretty(T obj) {
        try {
            return OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new JsonException(e);
        }
    }


    /**
     * 字符串转换为自定义对象
     *
     * @param str   要转换的字符串
     * @param clazz 自定义对象的class对象
     * @return 自定义对象
     */
    public static <T> T string2Obj(String str, Class<T> clazz) {
        try {
            return OBJECT_MAPPER.readValue(str, clazz);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new JsonException(e);
        }
    }


    /**
     * json字符串转对象
     *
     * @param str           json字符串
     * @param typeReference
     * @param <T>           返回的类型
     * @return
     */
    public static <T> T string2Obj(String str, TypeReference<T> typeReference) {
        try {
            return OBJECT_MAPPER.readValue(str, typeReference);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new JsonException(e);
        }
    }

}

